package com.shop.mall.utils;

import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSONObject;

import sun.misc.BASE64Encoder;

/**
 * 签名工具类
 *
 * @author admin
 */
public class SignUtils {

    public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
    public static final String ENCODE_ALGORITHM = "SHA-256";

    public static void main(String[] args) throws Exception {
        // 公私钥对
        Map<String, String> keyMap = RSA.generateKeyBytes();
        System.out.println(keyMap.get(RSA.PUBLIC_KEY));
        System.out.println(keyMap.get(RSA.PRIVATE_KEY));
        PublicKey publicKey = RSA.getPublicKey(keyMap.get(RSA.PUBLIC_KEY));
        PrivateKey privateKey = RSA.getPrivateKey(keyMap.get(RSA.PRIVATE_KEY));
        Map<String, String> params = new HashMap<>();
        JSONObject Json = new JSONObject();
        Json.put("customerId", "65");
        params.put("customerId", "65");
        // 签名
        byte[] sing_byte = sign(privateKey, Json.toJSONString());
        // 验签
        verifySign(publicKey, params, sing_byte);
    }

    /**
     * 签名
     *
     * @param privateKey 私钥
     * @param params     明文
     * @return
     */
    public static byte[] sign(PrivateKey privateKey, Map<String, String> params) {
        return sign(privateKey, sortToString(params));
    }

    /**
     * 签名
     *
     * @param privateKey 私钥
     * @param plain_text 明文
     * @return
     */
    public static byte[] sign(PrivateKey privateKey, String plain_text) {
        MessageDigest messageDigest;
        byte[] signed = null;
        try {
            messageDigest = MessageDigest.getInstance(ENCODE_ALGORITHM);
            messageDigest.update(plain_text.getBytes());
            byte[] outputDigest_sign = messageDigest.digest();
            System.out.println("SHA-256加密后-----》" + bytesToHexString(outputDigest_sign));
            Signature Sign = Signature.getInstance(SIGNATURE_ALGORITHM);
            Sign.initSign(privateKey);
            Sign.update(outputDigest_sign);
            signed = Sign.sign();
            String sign = (new BASE64Encoder()).encode(signed);
            System.out.println("base64簽名" + sign);
            System.out.println("SHA256withRSA签名后-----》" + bytesToHexString(signed));
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            e.printStackTrace();
        }
        return signed;
    }

    /**
     * 验签
     *
     * @param publicKey 公钥
     * @param params    明文
     * @param signed    签名
     * @return
     */
    public static boolean verifySign(PublicKey publicKey, Map<String, String> params, byte[] signed) {
        return verifySign(publicKey, sortToString(params), signed);
    }

    /**
     * 验签
     *
     * @param publicKey  公钥
     * @param plain_text 明文
     * @param signed     签名
     */
    public static boolean verifySign(PublicKey publicKey, String plain_text, byte[] signed) {

        MessageDigest messageDigest;
        boolean SignedSuccess = false;
        try {
            messageDigest = MessageDigest.getInstance(ENCODE_ALGORITHM);
            messageDigest.update(plain_text.getBytes());
            byte[] outputDigest_verify = messageDigest.digest();
            // System.out.println("SHA-256加密后-----》"
            // +bytesToHexString(outputDigest_verify));
            Signature verifySign = Signature.getInstance(SIGNATURE_ALGORITHM);
            verifySign.initVerify(publicKey);
            verifySign.update(outputDigest_verify);
            SignedSuccess = verifySign.verify(signed);
            System.out.println("验证成功？---" + SignedSuccess);

        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            e.printStackTrace();
        }
        return SignedSuccess;
    }

    /**
     * bytes[]换成16进制字符串
     *
     * @param src
     * @return
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * Map参数 排序转字符串
     *
     * @param params
     * @return
     */
    private static String sortToString(Map<String, String> params) {

        List<String> list = new ArrayList<>();

        params.keySet().forEach(mapkey -> {
            String value = params.get(mapkey);
            if (value != null && !"".equals(value.trim()))
                list.add(new StringBuilder(mapkey).append("=").append(value).toString());
        });

        Collections.sort(list);

        return String.join("&", list);
    }
}
